package com.utry.netty.server;


import android.util.Log;

import com.utry.netty.client.JsonDecoder;
import com.utry.netty.client.JsonEncoder;
import com.utry.netty.intf.MessageServerCallback;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;


public class NettyServer {
    private static final String TAG = "NettyServer";

    //端口
    private static final int PORT = 7010;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;

    private MessageServerCallback messageServerCallback;

    /**
     * 启动tcp服务端
     */
    public void startServer() {
        try {
            bossGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup();
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //分隔符
                        ByteBuf delimiter = Unpooled.copiedBuffer("$".getBytes());

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //解决粘包
//                            pipeline.addLast(new DelimiterBasedFrameDecoder(65535, delimiter));
                            //添加发送数据编码器
//                            pipeline.addLast(new ServerEncoder());
//                            //添加解码器，对收到的数据进行解码
//                            pipeline.addLast(new ServerDecoder());

                            //解码
                            // 这里将LengthFieldBasedFrameDecoder添加到pipeline的首位，因为其需要对接收到的数据
                            // 进行长度字段解码，这里也会对数据进行粘包和拆包处理
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 0, 2));
                            //编码
                            // LengthFieldPrepender是一个编码器，主要是在响应字节数据前面添加字节长度字段
                            pipeline.addLast(new LengthFieldPrepender(2));

                            // 对经过粘包和拆包处理之后的数据进行json反序列化，从而得到User对象
                            pipeline.addLast(new JsonDecoder());
                            // 对响应数据进行编码，主要是将User对象序列化为json
                            pipeline.addLast(new JsonEncoder());
                            //添加数据处理
                            pipeline.addLast(new ServerHandler(messageServerCallback));
                        }
                    });
            //服务器启动辅助类配置完成后，调用 bind 方法绑定监听端口，调用 sync 方法同步等待绑定操作完成
            b.bind(PORT).sync();

            if (null != messageServerCallback) {
                messageServerCallback.messageServerCallback("TCP 服务启动成功 PORT = " + PORT);
            }

            Log.d(TAG, "TCP 服务启动成功 PORT = " + PORT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 优雅的关闭服务器
     */
    public void shutdown() {
        try {
            if (workerGroup != null)
                workerGroup.shutdownGracefully().sync();
            if (bossGroup != null)
                bossGroup.shutdownGracefully().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void setMessageServerCallback(MessageServerCallback messageServerCallback) {
        this.messageServerCallback = messageServerCallback;
    }

}
